package damon.swing;

//import net.sf.sockettest.*;

import damon.common.ConstantObject;
import damon.taskThread.WriteThread;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EtchedBorder;
import java.awt.*;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

/**
 * @author Akshathkumar Shetty
 */

public class WriteJPanel extends JPanel {

    private final String NEW_LINE = "\r\n";
    private ClassLoader cl = getClass().getClassLoader();
    public ImageIcon logo = new ImageIcon(
            WriteJPanel.class.getClassLoader().getResource("icons/tree.jpeg"));
    public Icon icon = new ImageIcon(
            WriteJPanel.class.getClassLoader().getResource("icons/tree.jpeg"));

    private JPanel topPanel;//上半部分
    private JPanel toPanel;

    private JPanel centerPanel; //下半部分
    private JPanel textPanel;   //输出文本区域

    private JPanel buttonPanel;//z最下方
    private JPanel sendPanel;//button的发送标签区域

    private JLabel ipLabel = new JLabel("IP Address");
    private JLabel logoLabel = new JLabel("OpcPoint v "+ConstantObject.VERSION, logo,
            JLabel.CENTER);
    private JTextField ipField = new JTextField("127.0.0.1", 20);
//    private JTextField ipField = new JTextField("10.56.38.60", 20);
//    private JTextField portField = new JTextField("102", 10);

    private JLabel DBLabel = new JLabel("DB");//db块Label
//    private JTextField DBField = new JTextField("2502", 10);//db输入框
    private JTextField DBField = new JTextField("127", 10);//db输入框

    private JLabel offSetLabel = new JLabel("offSet");//偏移量Label
    private JTextField offSetField = new JTextField("842", 10);//偏移量输入框

    private JLabel writeLenLabel = new JLabel("writeLen");//写入长度Label
    private JTextField writeLenField = new JTextField("2", 10);//写入长度输入框

     private JLabel writeDataLabel = new JLabel("writeData");//写入数据Label
    private JTextField writeDataField = new JTextField("4396", 10);//写入数据输入框

    private JLabel typeLabel = new JLabel("type");//类型Label
    private JComboBox typeBox = new JComboBox();//类型下拉框


    private JButton connectButton = new JButton("connect");//连接按钮

    private JLabel convLabel = new JLabel("Write msg");
    private Border connectedBorder = BorderFactory.createTitledBorder(new EtchedBorder(), "content");
    private JTextArea messagesField = new JTextArea();

    private JButton clearButton = new JButton("Clear");

    private GridBagConstraints gbc = new GridBagConstraints();

    private Socket socket;
    private WriteThread writeThread;
    protected final JFrame parent;

    public WriteJPanel(final JFrame parent) {

        this.parent = parent;
        Container cp = this;

        topPanel = new JPanel();
        toPanel = new JPanel();
        toPanel.setLayout(new GridBagLayout());

        //ip  lable
        gbc.insets = new Insets(2, 2, 2, 2);
        gbc.weighty = 0.0;
        gbc.weightx = 0.0;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbc.anchor = GridBagConstraints.EAST;
        gbc.fill = GridBagConstraints.NONE;
        toPanel.add(ipLabel, gbc);
        //ip  输入框
        gbc.weightx = 1.0; //streach
        gbc.gridx = 1;
        gbc.gridwidth = 2;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        //enter转到port
//        ActionListener ipListener = new ActionListener() {
//            public void actionPerformed(ActionEvent e) {
//                portField.requestFocus();
//            }
//        };
//        ipField.addActionListener(ipListener);
        toPanel.add(ipField, gbc);

        //db  lable
        gbc.weighty = 0.0;
        gbc.weightx = 0.0;
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbc.anchor = GridBagConstraints.EAST;
        gbc.fill = GridBagConstraints.NONE;
        toPanel.add(DBLabel, gbc);
        //db  输入框
        gbc.weightx = 1.0; //streach
        gbc.gridx = 1;
        gbc.gridy = 2;
        gbc.gridwidth = 2;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        toPanel.add(DBField, gbc);


        //offset  lable
        gbc.weighty = 0.0;
        gbc.weightx = 0.0;
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbc.anchor = GridBagConstraints.EAST;
        gbc.fill = GridBagConstraints.NONE;
        toPanel.add(offSetLabel, gbc);
        //offset  输入框
        gbc.weightx = 1.0; //streach
        gbc.gridx = 1;
        gbc.gridy = 3;
        gbc.gridwidth = 2;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        toPanel.add(offSetField, gbc);


        //读取长度  lable
        gbc.weighty = 0.0;
        gbc.weightx = 0.0;
        gbc.gridx = 0;
        gbc.gridy = 4;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
//        gbc.anchor = GridBagConstraints.EAST;
        gbc.fill = GridBagConstraints.NONE;
        toPanel.add(writeLenLabel, gbc);
        //读取长度  输入框
        gbc.weightx = 1.0; //streach
        gbc.gridx = 1;
        gbc.gridy = 4;
        gbc.gridwidth = 2;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        toPanel.add(writeLenField, gbc);


        //写入数据  lable
        gbc.weighty = 0.0;
        gbc.weightx = 0.0;
        gbc.gridx = 0;
        gbc.gridy = 5;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
//        gbc.anchor = GridBagConstraints.EAST;
        gbc.fill = GridBagConstraints.NONE;
        toPanel.add(writeDataLabel, gbc);
        //写入数据  输入框
        gbc.weightx = 1.0; //streach
        gbc.gridx = 1;
        gbc.gridy = 5;
        gbc.gridwidth = 2;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        toPanel.add(writeDataField, gbc);






        //type  lable TODO
        gbc.weighty = 0.0;
        gbc.weightx = 0.0;
        gbc.gridx = 0;
        gbc.gridy = 6;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbc.anchor = GridBagConstraints.EAST;
        gbc.fill = GridBagConstraints.NONE;
        toPanel.add(typeLabel, gbc);
        //type  多选框
        gbc.weightx = 1; //streach
        gbc.gridx = 1;
        gbc.gridy = 6;
        gbc.gridwidth = 1;//标签长度占用几个单元格，以整体布局为准
        gbc.fill = GridBagConstraints.HORIZONTAL;
        typeBox.addItem("number");
        typeBox.addItem("number unsigned");
        typeBox.addItem("chars");
        typeBox.addItem("real|lReal");
//        typeBox.setPreferredSize(new Dimension(1000,20));
        toPanel.add(typeBox, gbc);



        //连接按钮
        gbc.weightx = 0.0;
        gbc.gridx = 2;
        gbc.gridy = 7;
        gbc.gridwidth = 1;
        gbc.fill = GridBagConstraints.NONE;
        connectButton.setMnemonic('C');
        connectButton.setToolTipText("Start Connection");
        ActionListener connectListener = (e) -> {
            connect();

        };
        connectButton.addActionListener(connectListener);
        toPanel.add(connectButton, gbc);


        //清空按钮
        gbc.weightx = 0.0;
        gbc.gridx = 4;
        gbc.gridy = 7;
        gbc.gridwidth = 1;
        gbc.fill = GridBagConstraints.NONE;
        clearButton.setToolTipText("Clear conversation with host");
        clearButton.setMnemonic('b');

        ActionListener clearListener = (e) -> {messagesField.setText("");};
        clearButton.addActionListener(clearListener);
        toPanel.add(clearButton, gbc);


        toPanel.setBorder(BorderFactory.createTitledBorder(new EtchedBorder(), "Connect To"));
        topPanel.setLayout(new BorderLayout(10, 0));
        topPanel.add(toPanel);

        //logo
        logoLabel.setVerticalTextPosition(JLabel.BOTTOM);
        logoLabel.setHorizontalTextPosition(JLabel.CENTER);
        topPanel.add(logoLabel, BorderLayout.EAST);
        topPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 5, 10));

        //文本区
        textPanel = new JPanel();
        textPanel.setLayout(new BorderLayout(0, 5));
        textPanel.add(convLabel, BorderLayout.NORTH);
        messagesField.setEditable(false);
        JScrollPane jsp = new JScrollPane(messagesField);
        textPanel.add(jsp);
        textPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 0, 3));

        //文本区外部框架
        centerPanel = new JPanel();
        centerPanel.setLayout(new BorderLayout(0, 10));
        centerPanel.add(textPanel, BorderLayout.CENTER);

        CompoundBorder cb = new CompoundBorder(
                BorderFactory.createEmptyBorder(5, 10, 10, 10),
                connectedBorder);
        centerPanel.setBorder(cb);

        cp.setLayout(new BorderLayout(10, 0));
        cp.add(topPanel, BorderLayout.NORTH);
        cp.add(centerPanel, BorderLayout.CENTER);
    }


    public void connect(){
        if(socket != null){
            disconnect();
            return;
        }


        String ip = ipField.getText();
        //校验ip
        if("".equals(ip)) {
            append("ip不能为空！");
            return;
        }
        //校验db
        try{
            int dbNum = Integer.valueOf(DBField.getText());
            if(dbNum<1 || dbNum>65535) {
                append("DB格式错误，范围：1<= db <=65535！");
                return;
            }
        }catch (Exception e){
            append("DB格式错误，非数字或数值过大，注意空格！");
            return;
        }
        //校验偏移量
        try{
            int offSet = Integer.valueOf(offSetField.getText());
            if(offSet<0 || offSet>2097151) {
                append("offSet格式错误，范围：0<= offset <=2097151！");
                return;
            }
        }catch (Exception e){
            append("offSet格式错误，非数字或数值过大，注意空格！");
            return;
        }
        //校验写入长度
        int writeLen;
        try{
            writeLen = Integer.valueOf(writeLenField.getText());

        }catch (Exception e){
            append("writeLen格式错误，非数字或数值过大，注意空格！");
            return;
        }
        //校验写入数据
        String writeData = writeDataField.getText();
       if("".equals(writeData)){
           append("writeData不能为空！");
       }

        //校验数据类型
        String writeType = typeBox.getSelectedItem().toString();
        if("chars".equals(writeType)){
            //char类型下长度校验
            if(writeLen<1 || writeLen>491) {
                append("writeLen格式错误，范围：1<= readLen <=491！");
                return;
            }
            //char类型下输入数据校验，只允许ascii
            for(char c : writeData.toCharArray()){
                if(c>255){
                    append("writeData内容错误，范围：ascii内字符！禁止输入中文！");
                    return;
                }
            }
            //char类型下数据长度和写字节是否对应
            if(writeData.length()!=writeLen){
                append("writeData长度和writeLen不相同！注意空格！");
                return;
            }
        }else if("real|lReal".equals(writeType)){
            //浮点数长度校验
            if(writeLen!=4 && writeLen !=8) {
                append("writeLen格式错误，当type为real|lReal时，readLen只能为4、8");
                return;
            }
            //4位浮点数输入内容校验
            if(writeLen==4){
                try{
                    float f = Float.parseFloat(writeData);
                    if(f<-Float.MAX_VALUE || f>Float.MAX_VALUE){
                        append("输入内容超出4位浮点数范围，正负1.4E-45<=real<=3.4028235E38");
                        return;
                    }
                }catch (Exception e){
                    append("非real类型，real为4位浮点数！");
                    return;
                }

            }
            //8位浮点数输入内容校验
            if(writeLen==8){
                try{
                    double d = Double.valueOf(writeData);
                    if(d<-Double.MAX_VALUE || d>Double.MAX_VALUE){
                        append("输入内容超出8位浮点数范围，正负4.9E-324<=long real<=1.7976931348623157E308");
                        return;
                    }
                }catch (Exception e){
                    append("非long real类型，long real为8位浮点数！");
                    return;
                }

            }

        } else{
            //整数类型长度校验
            if(writeLen!=1 && writeLen !=2 && writeLen!=4) {
                append("writeLen格式错误，当type为number或number unsigned时，readLen只能为1、2、4");
                return;
            }
            long l;
            try{
                l = Long.valueOf(writeData);
            }catch (NumberFormatException e){
                append("writeData格式错误，非数字或数值过大！");
                return;
            }


            if("number".equals(writeType)){
                if(writeLen==1){
                    if(l<Byte.MIN_VALUE || l>Byte.MAX_VALUE){
                        append("输入内容超出1个字节有符号整数范围，-128<=num<=127");
                        return;
                    }
                }
                if(writeLen==2){
                    if(l<-32768 || l>32767){
                        append("输入内容超出2个字节有符号整数范围，-32768<=num<=32767");
                        return;
                    }
                }
                if(writeLen==4){
                    if(l<Integer.MIN_VALUE || l>Integer.MAX_VALUE){
                        append("输入内容超出4个字节有符号整数范围，-2147483648<=num<=2147483647");
                        return;
                    }
                }

            }

            if("number unsigned".equals(writeType)){
                if(writeLen==1){
                    if(l<0 || l>255){
                        append("输入内容超出1个字节无符号整数范围范围，0<=num<=255");
                        return;
                    }
                }

                if(writeLen==2){
                    if(l<0 || l>65535){
                        append("输入内容超出2个字节无符号整数范围范围，0<=num<=65535");
                        return;
                    }
                }

                if(writeLen==4){
                    if(l<0 || l>4294967295l){
                        append("输入内容超出4个字节无符号整数范围范围，0<=num<=4294967295");
                        return;
                    }
                }
            }
        }
        try {
            socket = new Socket();
            SocketAddress socketAddress = new InetSocketAddress(ip, 102);
            socket.connect(socketAddress, 3000);
        } catch (IOException e) {
            e.printStackTrace();
            append("plc连接超时，超时时间3s！检查服务端是否开启！");
            socket= null;
            return;
        }
        if (writeThread != null) {
            if(writeThread.getSocket()!=null){
                try {
                    writeThread.getSocket().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            writeThread.setSocket(null);
        }
        writeThread = new WriteThread(this,socket);



        connectButton.setText("disconnect");

    }

    public synchronized void disconnect() {
//        append("socket!=null");
        writeThread.setRunIs(false);
        socket = null;
        connectButton.setText("connect");
    }

    public void append(String msg) {
        messagesField.append(msg + NEW_LINE);
        messagesField.setCaretPosition(messagesField.getText().length());
    }



    public JTextField getOffSetField() {
        return offSetField;
    }

    public JTextField getWriteLenField() {
        return writeLenField;
    }

    public JComboBox getTypeBox() {
        return typeBox;
    }

    public JTextField getDBField() {
        return DBField;
    }

    public JTextField getWriteDataField() {
        return writeDataField;
    }
}
